#include "dht11.h"
#include <basic.h>
#include <gpio.h>


GPIO_Port DHT11_PIN_PORT = GPIO_PORT_1;
GPIO_Pin DHT11_PIN_PIN = GPIO_PIN_0;

void dht11_Init(GPIO_Port port, GPIO_Pin pin)
{
    DHT11_PIN_PORT = port;
    DHT11_PIN_PIN = pin;
    GPIO_Init(DHT11_PIN_PORT, DHT11_PIN_PIN, GPIO_MODE_QUASI_BIDIRECTIONAL);
}

static void pinSet(void *a, bool ishigh)
{
    GPIO_Set(DHT11_PIN_PORT, DHT11_PIN_PIN, (GPIO_State)ishigh);
}
static bool pinGet(void *a)
{
    return (bool)GPIO_Get(DHT11_PIN_PORT, DHT11_PIN_PIN);
}

static uint8_t dht11_readByte()
{
    uint8_t value = 0, c = 0;
    int8_t i = 0;

    for (i = 0; i < 8; i++)
    {
        while (pinGet(NULL) == 0)
        {
            c++;
            if (c >= DHT11_TIME_OUT_DELAY)
            {
                return DHT11_ERROR_TIMEOUT;
            }
        }
        c = 0;
        delay_us(30);
        if (pinGet(NULL) == 1)
        {
            value |= (1 << (7 - i));
        }
        while (pinGet(NULL) == 1)
        {
            c++;
            if (c >= DHT11_TIME_OUT_DELAY)
            {
                return DHT11_ERROR_TIMEOUT;
            }
            delay_us(1);
        }
    }

    return value;
}
static bool dht11_startSignal()
{
    pinSet(NULL, 1);
    delay(100);

    // begin
    pinSet(NULL, 0);
    delay(25);

    pinSet(NULL, 1);

    delay_us(30);

    return pinGet(NULL) == 0;
}

static uint8_t dht11_readRawData(uint8_t *dat)
{
    int8_t i = 0;
    uint8_t c = 0;
    delay(DHT11_CONSECUTIVE_DELAY);

    if (dht11_startSignal())
    {
        while (pinGet(NULL) == 0) // Wait pull up
        {
            c++;
            if (c >= DHT11_TIME_OUT_DELAY)
            {
                return DHT11_ERROR_TIMEOUT;
            }
            delay_us(1);
        }
        c = 0;

        if (pinGet(NULL) == 1)
        {
            while (pinGet(NULL) == 1)
            {
                c++;
                if (c >= DHT11_TIME_OUT_DELAY)
                {
                    return DHT11_ERROR_TIMEOUT;
                }
                delay_us(1);
            }
            for (i = 0; i < 5; i++)
                dat[i] = dht11_readByte();

            for (i = 0; i < 5; i++)
                if (dat[i] == DHT11_ERROR_TIMEOUT)
                    return DHT11_ERROR_TIMEOUT;

            if (dat[4] == dat[0] + dat[1] + dat[2] + dat[3])
                return 0;
            else
                return DHT11_ERROR_CHECKSUM;
        }
    }
    else
        return DHT11_ERROR_START;

    return 0;
}

 uint8_t dht11_TemperatureHumidity(uint8_t *temp, uint8_t *humidity)
{
    uint8_t dat[5] = {0}, error;

    error = dht11_readRawData(dat);
    if (error != 0)
        return error;

    if (temp)
        *temp = dat[2];
    if (humidity)
        *humidity = dat[0];

    return 0;
}
